package com.ilxqx.framework.system.util;

import com.ilxqx.framework.security.po.SimpleUserInfo;
import com.ilxqx.framework.system.constant.TableFieldConstants;
import com.ilxqx.framework.system.form.anno.Pk;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 反射工具类
 * @author venus
 */
@Slf4j
public final class ReflectionUtils {

    /**
     * 通过反射获取属性的值
     * @param field 属性反射对象
     * @param instance 实例对象
     * @return 属性值
     */
    @Nullable
    public static Object getFieldValue(@NotNull Field field, @NotNull Object instance) {
        Class<?> cls = instance.getClass();
        // 优先从get方法中获取值
        try {
            Method method = cls.getDeclaredMethod("get" + StringUtils.capitalize(field.getName()));
            return method.invoke(instance);
        } catch (NoSuchMethodException e) {
            // get方法不存在，将使用直接获取
            field.setAccessible(true);
            try {
                // 直接通过属性获取
                return field.get(instance);
            } catch (IllegalAccessException ex) {
                log.warn("通过反射获取[{}]类的[{}]属性出现错误：{}", cls.getName(), field.getName(), ex);
                return null;
            }
        } catch (IllegalAccessException | InvocationTargetException e) {
            // 执行get方法出现错误
            log.warn("通过反射使用get方法获取[{}]类的[{}]属性出现错误：{}", cls.getName(), field.getName(), e);
            return null;
        }
    }

    /**
     * 通过反射设置一个对象的属性
     * @param field 属性反射对象
     * @param instance 对象实例
     * @param value 需设置的值
     */
    public static void setFieldValue(@NotNull Field field, @NotNull Object instance, Object value) {
        Class<?> cls = instance.getClass();
        // 优先从set方法中设置值
        try {
            Method method = cls.getDeclaredMethod("set" + StringUtils.capitalize(field.getName()), field.getType());
            method.invoke(instance, value);
        } catch (NoSuchMethodException e) {
            // set方法不存在，将使用直接设置
            field.setAccessible(true);
            try {
                // 直接通过属性设置
                field.set(instance, value);
            } catch (IllegalAccessException ex) {
                log.warn("通过反射设置[{}]类的[{}]属性出现错误：{}", cls.getName(), field.getName(), ex);
            }
        } catch (IllegalAccessException | InvocationTargetException e) {
            // 执行set方法出现错误
            log.warn("通过反射使用set方法设置[{}]类的[{}]属性出现错误：{}", cls.getName(), field.getName(), e);
        }
    }

    /**
     * 设置实体对象的操作用户信息
     * @param entity 实体对象
     * @param simpleUserInfo 操作用户信息对象
     */
    public static void setEntityOperationUserSimpleInfo(@NotNull Object entity, SimpleUserInfo simpleUserInfo) {
        Class<?> cls = entity.getClass();
        Field operationUserId = org.springframework.util.ReflectionUtils.findField(cls, TableFieldConstants.OPERATION_USER_ID_FIELD_NAME);
        Field operationUserName = org.springframework.util.ReflectionUtils.findField(cls, TableFieldConstants.OPERATION_USER_NAME_FIELD_NAME);
        if (operationUserId == null || operationUserName == null) {
            // 没有找到
            return;
        }

        // 设置属性
        ReflectionUtils.setFieldValue(operationUserId, entity, simpleUserInfo.getUserId());
        ReflectionUtils.setFieldValue(operationUserName, entity, simpleUserInfo.getUserName());
    }

    /**
     * 获取实体对象操作用户的信息
     * @param entity 实体对象
     * @return 操作用户简要信息
     */
    public static SimpleUserInfo getEntityOperationUserSimpleInfo(@NotNull Object entity) {
        Class<?> cls = entity.getClass();
        Field operationUserId = org.springframework.util.ReflectionUtils.findField(cls, TableFieldConstants.OPERATION_USER_ID_FIELD_NAME);
        Field operationUserName = org.springframework.util.ReflectionUtils.findField(cls, TableFieldConstants.OPERATION_USER_NAME_FIELD_NAME);
        if (operationUserId == null || operationUserName == null) {
            // 没有用户ID和姓名任意一个字段都将返回null
            return null;
        }

        SimpleUserInfo operationUserSimpleInfo = new SimpleUserInfo();
        operationUserSimpleInfo.setUserId((Long) ReflectionUtils.getFieldValue(operationUserId, entity));
        operationUserSimpleInfo.setUserName((String) ReflectionUtils.getFieldValue(operationUserName, entity));
        return operationUserSimpleInfo;
    }

    /**
     * 实例化一个对象
     * @param cls 类
     * @return 对象
     */
    public static <T> T newInstance(Class<? extends T> cls) {
        // 获取默认无参构造器
        try {
            return cls.getDeclaredConstructor().newInstance();
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            log.error("通过反射实例化对象[{}]失败：{}", cls.getName(), e);
        }
        return null;
    }

    /**
     * 获取formData的主键
     * @param formData 表单数据
     * @return 主键
     */
    public static Object getFormDataPk(Object formData) {
        Field[] fields = formData.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(Pk.class)) {
                return ReflectionUtils.getFieldValue(field, formData);
            }
        }
        return null;
    }

    /**
     * 获取一个对象中具有某个注解的所有反射字段对象
     * @param cls 类
     * @param annotation 注解标识
     * @return 字段List
     */
    public static List<Field> getAnnotatedFields(Class<?> cls, Class<? extends Annotation> annotation) {
        Field[] fields = cls.getDeclaredFields();
        return Arrays.stream(fields)
            .filter(field -> field.isAnnotationPresent(annotation))
            .collect(Collectors.toList());
    }

}
